package eva.savant.core.view

import com.google.zxing.BarcodeFormat
import com.google.zxing.client.j2se.MatrixToImageWriter
import com.google.zxing.qrcode.QRCodeWriter
import eva.savant.businessobject.Entity
import eva.savant.businessobject.gl.Parametro
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.DateUtil
import org.primefaces.model.DefaultStreamedContent
import org.primefaces.model.StreamedContent

import javax.persistence.Column
import java.lang.reflect.Field
import java.lang.reflect.Method
import javax.faces.event.ActionEvent
import java.lang.annotation.Annotation
import org.primefaces.event.SelectEvent
import javax.faces.bean.ManagedBean
import org.apache.poi.hssf.usermodel.*
import org.apache.poi.hssf.util.HSSFColor

import java.text.SimpleDateFormat

public abstract class Bean extends Base {

  def isRead= false

  def config= false

  def dialog= false

  def filter= false

  def form = true

  def focus= null

  def name= null

  def entity

  def lsEntity

  def entitySel

  def entityLsProperty

  def entityLsField

  def entitySelField

  List<Entity> selEntity

  List<Object> lsFiltered

  public void createEntityProperty(Class clazz) {

    println 'Crete property for the ' + clazz

    entityLsProperty= new HashMap<String,List>()

    entityLsField= new ArrayList<String>()


    for(x in clazz.getDeclaredFields() ) {

    if(x.type.name.equals('java.util.Collection')) continue

    def column= x.getAnnotation(Column.class)

    def  size= column != null? column.length() : null

    entityLsField.add x.name; println 'prop: '+x.name+' t: '+x.type.name+' z: '+size

    entityLsProperty.put(x.name,[x.name,x.type.name,size]) }
  }

  public void init() {

    if(entityLsProperty == null)

    createEntityProperty(entity.class)
  }


  public void uiClean(ActionEvent event) { try {

    form= true

    filter= false

    isRead= false

    cleanEntity()

    cleanFilter()

    lsFiltered= null

  } catch (Exception e) { addErrorMessage e } }


  public void uiFind(ActionEvent event) { try {

    form= false

    config= false

    lsEntity= findLsEntity()

  } catch (Exception e) { addErrorMessage e } }


  public void uiEdit(ActionEvent event) { try {

    if(selEntity == null || selEntity.size() < 1) return

    form= true; editEntity(selEntity[0].id)

  } catch (Exception e) { addErrorMessage e } }


  public void uiRowEdit(SelectEvent event) {

    form= true; editEntity(event.getObject().id)
  }

  public void detailEdit(SelectEvent event) {

  }

  public void uiMerge(ActionEvent event) { try {

    if(entity == null) { mergeEntity(entity); return }

    entity.operacionId= ALTA


    if(entity instanceof Entity) {

    entity.sociedadId= sociedad.id

    entity.usuarioId= usuario.id }


    def c; try { c= entity.class.getDeclaredField('codigo'); def t= Field.getTypeName(entity.class.getDeclaredField('id').type)

    if(t.equals('java.lang.String') && c != null) entity.id= sociedad.id + entity.codigo } catch (Exception ignore) { c= null }


    form= true; if(mergeEntity(entity))  { def id= c==null? entity.id : entity.codigo; id= id!=null? id : ''

    addInfoMessage 'Se registro correctamente la TRANSACCION ' + id; cleanEntity(); lsFiltered= null }


    if(lsEntity?.size() > 0) uiFind(null); form= true

  } catch (Exception e) { addErrorMessage e } }


  public void uiRemove(ActionEvent event) { try {

    for(entity in lsEntity) {

    entity.operacionId= BAJA


    if(entity instanceof Entity) {

    entity.sociedadId= sociedad.id

    entity.usuarioId= usuario.id }


    removeEntity(entity) }


    for(entity in selEntity) {

    entity.operacionId= BAJA


    if(entity instanceof Entity) {

    entity.sociedadId= sociedad.id

    entity.usuarioId= usuario.id }


    removeEntity(entity) }


    cleanEntity(); uiFind(null)

    lsFiltered= selEntity= null

  } catch (Exception e) { addErrorMessage e } }


  public void uiPrint(ActionEvent event) { try { actionPrint() } catch (Exception e) { addErrorMessage e } }

  public void uiCleanPrint(ActionEvent event) { try { cleanPrint() } catch (Exception e) { addErrorMessage e } }

  public void uiForm(ActionEvent event) { form= !form }


  public void uiDialog(ActionEvent event) { dialog= !dialog }


  public void uiFilter(ActionEvent event) { filter= !filter }


  public void uiConfig(ActionEvent event) { config= !config }



  public void actionPrint() throws Exception { }

  public void cleanPrint() throws Exception { }

  public void cleanEntity() throws Exception { }


  public List findLsEntity() throws Exception { return null }


  public void editEntity(Object value) throws Exception { }


  public boolean mergeEntity(Object entity) throws Exception { return false }


  public void removeEntity(Object entity) throws Exception { }


  public void cleanFilter() throws Exception { }



  public String getRootPath() {

    return getClass().getResource('/').path.replace('WEB-INF/classes/','')
  }


  public static String getResourcePath() {

    return get(Parametro.class,'nombre=?','app.resource')?.valor
  }


  public InputStream readFilePackage(String path) {

    return getClass().classLoader.getResourceAsStream('/' + path)
  }


  public static String trimZero(String text) {

    return text.replaceFirst ('^0*','').trim()
  }


  public static double round(double value, int numDecimal) {

     double factor = Math.pow(10, numDecimal)

     return Math.round(value * factor) / factor
  }


  public static Date toDate(String date, String format) {

    try { return new SimpleDateFormat(format).parse(date)   }

    catch ( Exception ignore ) { return null }
  }


  public static String toDate(Long date, String format) {

    def sdf=new SimpleDateFormat(format)

    return sdf.format(new Date(date))
  }


  public static Integer toInteger(String text) {

    try { return new Integer(text) }

    catch ( Exception ignore ) { return -1 }
  }


  public static BigDecimal toBigDecimal(String text) {

    try { return new BigDecimal(text) }

    catch ( Exception ignore ) { return -1 }
  }


  public static Date toStartDay(Date dateEnd) {

    def day= Calendar.instance; day.setTime(dateEnd)

    day.set(Calendar.HOUR_OF_DAY,00)

    day.set(Calendar.MINUTE,00)

    day.set(Calendar.SECOND,00)

    return day.time
  }


  public static Date toMidnight(Date dateEnd) {

    def day= Calendar.instance; day.setTime(dateEnd)

    day.set(Calendar.HOUR_OF_DAY,23)

    day.set(Calendar.MINUTE,59)

    day.set(Calendar.SECOND,59)

    return day.time
  }


  public static void processXLS(Object document) {

    def wb= (HSSFWorkbook) document

    def sheet = wb.getSheetAt(0)

    def header= sheet.getRow(0)


    def cellStyle= wb.createCellStyle()

    cellStyle.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index)

    cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND)


    def font = wb.createFont()

    font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD)

    cellStyle.setFont(font)


    for(int i=0; i < header.physicalNumberOfCells; i++)

    header.getCell(i).setCellStyle(cellStyle);
  }


  public String getName() {

    if(name == null) name= getAnnotationValue(this.class,ManagedBean,'name'); return name
  }


  @SuppressWarnings("unchecked")
  public static<T> T getAnnotationValue(Class<?> clazz, Class<? extends Annotation> annotationClass, String element) throws Exception {

    Annotation annotation = clazz.getAnnotation(annotationClass);

    Method method = annotationClass.getMethod(element,(Class[])null);

    if (annotation == null) return((T)method.getDefaultValue());

    return((T)method.invoke(annotation,(Object[])null));
  }


  public static String getNextCode(Class<?> tClass) throws Exception {

    def list= find(tClass,''), id= 0


    for(x in list) {

    def n= new Integer(trimZero(x.codigo)); id= n > id? n : id }


    if(id > 99) throw new Exception('El numero maximo de codigos permitido es 99')


    id= id + 1; return id < 10? '0' + id : id + ''
  }

  public boolean getEntityHasCode() {
      try {
    return entity.class.getDeclaredField('codigo') != null
      } catch (Exception ignore) { return false}
  }

  public String getLengthEP(String property) {

    if( !property.contains('.') ) return getLength(entity.class, property); def aux= property.split('\\.')

    def tClass= entity.class.getDeclaredField(aux[0].toLowerCase()).type

    return getLength(tClass, aux[1])
  }

  public static Integer getLength(Class tClass, String property) {

    println 'tClass: '+tClass+ ' property: '+property

    def field= tClass.getDeclaredField(property.toLowerCase())

    return  field != null? field.getAnnotation(Column.class).length() : null
  }

  public static BigDecimal numericCell(HSSFRow row, int i) {

    def cell= row.getCell(i)

    return cell.cellType == Cell.CELL_TYPE_NUMERIC? new BigDecimal(cell.numericCellValue)  :

           cell.cellType == Cell.CELL_TYPE_STRING?  new BigDecimal(cell.stringCellValue) : 0
  }

  public static java.sql.Date dateCell(HSSFRow row, int i) {

    def cell= row.getCell(i)

    return DateUtil.isCellDateFormatted(cell)? new java.sql.Date(cell.dateCellValue.time) : null
  }

  public static Integer integerCell(HSSFRow row, int i) {

    def cell= row.getCell(i)

    return cell.cellType == Cell.CELL_TYPE_NUMERIC?  (Integer) cell.numericCellValue  :

           cell.cellType == Cell.CELL_TYPE_STRING?  new Integer(cell.stringCellValue) : 0
  }

  public static String stringCell(HSSFRow row, int i) {

    def cell= row.getCell(i)

    return cell == null? '' :

           cell.cellType == Cell.CELL_TYPE_NUMERIC? cell?.numericCellValue + '' :

           cell.cellType == Cell.CELL_TYPE_STRING? cell?.stringCellValue : ''
  }

  public static ByteArrayInputStream getByteArrayQRCode(String txt) throws IOException {

    def i= new ByteArrayOutputStream()

    MatrixToImageWriter.writeToStream(new QRCodeWriter().encode(txt,BarcodeFormat.QR_CODE,80,80),'png',i)

    return new ByteArrayInputStream(i.toByteArray())
  }

  public static StreamedContent getQRCode(String txt) throws IOException {

    return new DefaultStreamedContent(getByteArrayQRCode(txt),'image/png')
  }

}
